package com.cyr.daletou.service;

import com.cyr.daletou.dao.SsqRepository;
import com.cyr.daletou.dao.model.SsqHistoryEntity;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author chenyanrui
 * @since 2021/6/14
 */
@Slf4j
@Service
public class SsqService {
    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @Autowired
    private SsqFeignClient ssqFeignClient;

    @Autowired
    private SsqRepository ssqRepository;

    public List<SsqHistoryEntity> getAll() {
        return ssqRepository.findAll();
    }

    public Page<SsqHistoryEntity> findByPage(int pageIndex, int pageSize) {
        return ssqRepository.findAll(PageRequest.of(pageIndex, pageSize, Sort.Direction.DESC));
    }

    @Transactional
    public Object fetch(int start, int end) {
        DecimalFormat decimalFormat = new DecimalFormat("#,#,#");
        String fetch = ssqFeignClient.fetch(start, end);
        Document document = Jsoup.parse(fetch);
        Element tdata = document.body().getElementById("tdata");
        List<Node> nodes = tdata.childNodes().subList(1, tdata.childNodes().size() - 1);
        List<SsqHistoryEntity> collect = nodes.stream()
                .map(Node::childNodes)
                .map(dataNodes -> {
                    SsqHistoryEntity entity = new SsqHistoryEntity();
                    String id = dataNodes.get(1).childNode(0).toString();
                    entity.setId(id);
                    entity.setR1(Integer.parseInt(dataNodes.get(2).childNode(0).toString()));
                    entity.setR2(Integer.parseInt(dataNodes.get(3).childNode(0).toString()));
                    entity.setR3(Integer.parseInt(dataNodes.get(4).childNode(0).toString()));
                    entity.setR4(Integer.parseInt(dataNodes.get(5).childNode(0).toString()));
                    entity.setR5(Integer.parseInt(dataNodes.get(6).childNode(0).toString()));
                    entity.setR6(Integer.parseInt(dataNodes.get(7).childNode(0).toString()));
                    entity.setB1(Integer.parseInt(dataNodes.get(8).childNode(0).toString()));
                    try {
                        entity.setJackpot(decimalFormat.parse(dataNodes.get(10).childNode(0).toString()).intValue());
                    } catch (ParseException e) {
                        log.warn("id[{}] Jackpot format failed", id);
                    }
                    entity.setLv1Qty(Integer.parseInt(dataNodes.get(11).childNode(0).toString()));
                    try {
                        entity.setLv1Bonus(decimalFormat.parse(dataNodes.get(12).childNode(0).toString()).intValue());
                    } catch (ParseException e) {
                        log.warn("id[{}] Lv1Bonus format failed", id);
                    }
                    entity.setLv2Qty(Integer.parseInt(dataNodes.get(13).childNode(0).toString()));
                    try {
                        entity.setLv2Bonus(decimalFormat.parse(dataNodes.get(14).childNode(0).toString()).intValue());
                    } catch (ParseException e) {
                        log.warn("id[{}] Lv2Bonus format failed", id);
                    }
                    try {
                        entity.setTotalBonus(decimalFormat.parse(dataNodes.get(15).childNode(0).toString()).intValue());
                    } catch (ParseException e) {
                        log.warn("id[{}] TotalBonus format failed", id);
                    }
                    String date = dataNodes.get(16).childNode(0).toString();
                    LocalDate localDate = LocalDate.parse(date, DATE_FORMAT);
                    entity.setDrawDate(Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
                    return entity;
                })
                .collect(Collectors.toList());
        ssqRepository.saveAll(collect);
        return collect;
    }

    public Object countR1() {
        List<SsqHistoryEntity> list = ssqRepository.findAll();
        Map<Integer, Long> collect = list.stream().collect(Collectors.groupingBy(SsqHistoryEntity::getR1, Collectors.counting()));
        return collect;
    }

    public Object countTop3() {
        List<SsqHistoryEntity> list = ssqRepository.findAll();
        Map<Integer, Long> r1 = getCollect(list, SsqHistoryEntity::getR1);
        Map<Integer, Long> r2 = getCollect(list, SsqHistoryEntity::getR2);
        Map<Integer, Long> r3 = getCollect(list, SsqHistoryEntity::getR3);
        Map<Integer, Long> r4 = getCollect(list, SsqHistoryEntity::getR4);
        Map<Integer, Long> r5 = getCollect(list, SsqHistoryEntity::getR5);
        Map<Integer, Long> r6 = getCollect(list, SsqHistoryEntity::getR6);
        Map<Integer, Long> b1 = getCollect(list, SsqHistoryEntity::getB1);
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("r1", r1);
        map.put("r2", r2);
        map.put("r3", r3);
        map.put("r4", r4);
        map.put("r5", r5);
        map.put("r6", r6);
        map.put("b1", b1);
        return map;
    }

    private LinkedHashMap<Integer, Long> getCollect(List<SsqHistoryEntity> list, Function<SsqHistoryEntity, Integer> getFunc) {
        return list.stream().collect(Collectors.groupingBy(getFunc, LinkedHashMap::new, Collectors.counting()))
                .entrySet().stream()
                .sorted(Map.Entry.<Integer, Long>comparingByValue().reversed())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (o, n) -> n, LinkedHashMap::new));
    }
}
